from typing import Optional, List, Tuple, Dict, Any
from tortoise.exceptions import DoesNotExist
from app.modules.roles.models import RoleModel
from app.modules.roles.schemas import (
    RoleCreateInput, RoleCreatedResponse, RoleUpdate, 
    RoleInfo, RoleDetailInfo, RoleQueryParams, RoleUserInfo
)
from app.core.exceptions import BusinessException, NotFoundException


class RoleService:
    """角色服务类"""

    @staticmethod
    async def get_by_id(role_id: int) -> Optional[RoleModel]:
        """通过ID获取角色"""
        role = await RoleModel.get_or_none(id=role_id)
        if not role:
            raise NotFoundException(message="角色不存在")
        return role

    @staticmethod
    async def get_by_code(code: str) -> Optional[RoleModel]:
        """通过编码获取角色"""
        return await RoleModel.get_or_none(code=code)

    @staticmethod
    async def get_role_list(
        skip: int = 0, 
        limit: int = 10,
        query_params: Optional[RoleQueryParams] = None
    ) -> Tuple[int, List[RoleInfo]]:
        """获取角色列表（带分页和查询条件）"""
        query = RoleModel.all()
        
        # 应用查询条件
        if query_params:
            if query_params.name:
                query = query.filter(name__icontains=query_params.name)
            if query_params.code:
                query = query.filter(code__icontains=query_params.code)
            if query_params.is_active is not None:
                query = query.filter(is_active=query_params.is_active)
            if query_params.is_system is not None:
                query = query.filter(is_system=query_params.is_system)
        
        total = await query.count()
        roles = await query.offset(skip).limit(limit).order_by('sort_order', 'id')
        
        # 转换为Pydantic模型
        role_info_list = [RoleInfo.from_orm(role) for role in roles]
        return total, role_info_list

    @staticmethod
    async def create_role(role_data: RoleCreateInput) -> RoleCreatedResponse:
        """创建角色"""
        # 检查角色编码是否已存在
        if await RoleService.get_by_code(role_data.code):
            raise BusinessException(message="角色编码已存在")
        
        # 验证权限编码是否存在
        if role_data.permissions:
            from app.modules.permissions.models import PermissionModel
            existing_permissions = await PermissionModel.filter(
                code__in=role_data.permissions, 
                is_active=True
            )
            existing_codes = [p.code for p in existing_permissions]
            invalid_codes = set(role_data.permissions) - set(existing_codes)
            if invalid_codes:
                raise BusinessException(message=f"权限编码不存在: {', '.join(invalid_codes)}")
        
        role = await RoleModel.create(**role_data.dict())
        
        return RoleCreatedResponse(
            id=role.id,
            name=role.name,
            code=role.code
        )

    @staticmethod
    async def update_role(role_id: int, role_data: RoleUpdate) -> RoleInfo:
        """更新角色信息"""
        role = await RoleService.get_by_id(role_id)
        
        # 检查是否为系统角色
        if role.is_system:
            raise BusinessException(message="系统角色不允许修改")
        
        # 检查角色编码是否重复（排除自己）
        if role_data.code and role_data.code != role.code:
            existing_role = await RoleService.get_by_code(role_data.code)
            if existing_role:
                raise BusinessException(message="角色编码已存在")
        
        # 验证权限编码是否存在
        if role_data.permissions is not None:
            from app.modules.permissions.models import PermissionModel
            existing_permissions = await PermissionModel.filter(
                code__in=role_data.permissions, 
                is_active=True
            )
            existing_codes = [p.code for p in existing_permissions]
            invalid_codes = set(role_data.permissions) - set(existing_codes)
            if invalid_codes:
                raise BusinessException(message=f"权限编码不存在: {', '.join(invalid_codes)}")
        
        # 更新角色信息
        update_data = role_data.dict(exclude_unset=True)
        for key, value in update_data.items():
            setattr(role, key, value)
        await role.save()
        
        return RoleInfo.from_orm(role)

    @staticmethod
    async def delete_role(role_id: int) -> None:
        """删除角色"""
        role = await RoleService.get_by_id(role_id)
        
        # 检查是否为系统角色
        if role.is_system:
            raise BusinessException(message="系统角色不允许删除")
        
        # 检查是否有用户使用此角色
        from app.modules.users.models import UserModel
        users_with_role = await UserModel.filter(role_id=role_id)
        if users_with_role:
            raise BusinessException(message="有用户正在使用此角色，无法删除")
        
        await role.delete()

    @staticmethod
    async def get_role_detail(role_id: int) -> RoleDetailInfo:
        """获取角色详细信息（包含权限对象）"""
        role = await RoleService.get_by_id(role_id)
        
        # 获取权限对象
        permission_objects = await role.get_permission_objects()
        permission_data = [
            {
                'id': p.id,
                'name': p.name,
                'code': p.code,
                'type': p.type
            } for p in permission_objects
        ]
        
        return RoleDetailInfo(
            id=role.id,
            name=role.name,
            code=role.code,
            description=role.description,
            permissions=role.permissions,
            permission_objects=permission_data,
            sort_order=role.sort_order,
            is_active=role.is_active,
            is_system=role.is_system,
            remark=role.remark,
            created_at=role.created_at,
            updated_at=role.updated_at
        )

    @staticmethod
    async def get_role_users(role_id: int, skip: int = 0, limit: int = 10) -> Tuple[int, List[RoleUserInfo]]:
        """获取角色的用户列表"""
        role = await RoleService.get_by_id(role_id)
        users = await role.get_users()
        
        total = len(users)
        paginated_users = users[skip:skip + limit]
        
        # 转换为Pydantic模型
        user_info_list = [RoleUserInfo.from_orm(user) for user in paginated_users]
        return total, user_info_list

    @staticmethod
    async def update_role_permissions(role_id: int, permissions: List[str]) -> RoleInfo:
        """更新角色权限"""
        role = await RoleService.get_by_id(role_id)
        
        # 检查是否为系统角色
        if role.is_system:
            raise BusinessException(message="系统角色不允许修改权限")
        
        # 验证权限编码是否存在
        if permissions:
            from app.modules.permissions.models import PermissionModel
            existing_permissions = await PermissionModel.filter(
                code__in=permissions, 
                is_active=True
            )
            existing_codes = [p.code for p in existing_permissions]
            invalid_codes = set(permissions) - set(existing_codes)
            if invalid_codes:
                raise BusinessException(message=f"权限编码不存在: {', '.join(invalid_codes)}")
        
        # 更新权限
        await role.sync_permissions(permissions)
        
        return RoleInfo.from_orm(role)

    @staticmethod
    async def add_role_permissions(role_id: int, permissions: List[str]) -> RoleInfo:
        """为角色添加权限"""
        role = await RoleService.get_by_id(role_id)
        
        # 检查是否为系统角色
        if role.is_system:
            raise BusinessException(message="系统角色不允许修改权限")
        
        # 验证权限编码是否存在
        if permissions:
            from app.modules.permissions.models import PermissionModel
            existing_permissions = await PermissionModel.filter(
                code__in=permissions, 
                is_active=True
            )
            existing_codes = [p.code for p in existing_permissions]
            invalid_codes = set(permissions) - set(existing_codes)
            if invalid_codes:
                raise BusinessException(message=f"权限编码不存在: {', '.join(invalid_codes)}")
        
        # 添加权限
        role.add_permissions(permissions)
        await role.save()
        
        return RoleInfo.from_orm(role)

    @staticmethod
    async def remove_role_permissions(role_id: int, permissions: List[str]) -> RoleInfo:
        """从角色移除权限"""
        role = await RoleService.get_by_id(role_id)
        
        # 检查是否为系统角色
        if role.is_system:
            raise BusinessException(message="系统角色不允许修改权限")
        
        # 移除权限
        role.remove_permissions(permissions)
        await role.save()
        
        return RoleInfo.from_orm(role)

    @staticmethod
    async def clear_role_permissions(role_id: int) -> RoleInfo:
        """清空角色权限"""
        role = await RoleService.get_by_id(role_id)
        
        # 检查是否为系统角色
        if role.is_system:
            raise BusinessException(message="系统角色不允许修改权限")
        
        # 清空权限
        role.clear_permissions()
        await role.save()
        
        return RoleInfo.from_orm(role)

    @staticmethod
    async def get_active_roles() -> List[RoleInfo]:
        """获取所有激活的角色"""
        roles = await RoleModel.get_active_roles()
        return [RoleInfo.from_orm(role) for role in roles]

    @staticmethod
    async def get_system_roles() -> List[RoleInfo]:
        """获取系统角色"""
        roles = await RoleModel.get_system_roles()
        return [RoleInfo.from_orm(role) for role in roles]

    @staticmethod
    async def get_custom_roles() -> List[RoleInfo]:
        """获取自定义角色"""
        roles = await RoleModel.get_custom_roles()
        return [RoleInfo.from_orm(role) for role in roles]

    @staticmethod
    async def get_roles_with_permissions() -> List[RoleDetailInfo]:
        """获取所有角色及其权限信息"""
        roles_data = await RoleModel.get_roles_with_permissions()
        return [RoleDetailInfo(**role_data) for role_data in roles_data]

    @staticmethod
    async def batch_update_roles(role_ids: List[int], update_data: Dict[str, Any]) -> None:
        """批量更新角色"""
        # 检查是否为系统角色
        system_roles = await RoleModel.filter(
            id__in=role_ids, 
            is_system=True
        )
        if system_roles:
            raise BusinessException(message="系统角色不允许批量修改")
        
        # 批量更新
        await RoleModel.filter(id__in=role_ids).update(**update_data)

    @staticmethod
    async def check_role_permission(role_id: int, permission_code: str) -> bool:
        """检查角色是否拥有指定权限"""
        role = await RoleService.get_by_id(role_id)
        return role.has_permission(permission_code)

    @staticmethod
    async def check_role_permissions(role_id: int, permission_codes: List[str], check_all: bool = False) -> bool:
        """检查角色是否拥有指定权限"""
        role = await RoleService.get_by_id(role_id)
        if check_all:
            return role.has_all_permissions(permission_codes)
        else:
            return role.has_any_permission(permission_codes)
